//////////////////////////////////////////////////////////////////////
// SceneManager.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Scene manager, owns a scenegraph, child to _CManagerBase
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <ManagerBase.h>
#include <SceneGraph.h>
#include <ITraverse.h>
#include <Logger.h>

namespace grflib
{
    namespace engine
    {
        namespace core
        {
            /////////////////////////////////////////////////
            // Scene manager class declaration
            template<typename TObj, typename TRenderQueue>
            class CSceneManager : public _CManagerBase<TObj>
            {
            public:
                CSceneManager() : m_pSceneGraph(0) {}
                virtual ~CSceneManager();

                //Inherited
                bool AddObj(const std::string &name, boost::shared_ptr<TObj> &pObj);
                void RemoveObj(const std::string &name);
                void Clear(void);

                //update world coord
                void UpdateWorldCoord(void);

                //traverse scenegraph
                HRESULT TraverseSceneGraph(const IMemberCaller<TObj> &func);
                //HRESULT TraverseSceneGraph(const IMemberPtrCaller<TObj> &func);

                //scene graph accessor
                CSceneGraph<TObj, TRenderQueue> *GetSceneGraphPtr(void) {return m_pSceneGraph;}
                bool SetSceneGraph(CSceneGraph<TObj, TRenderQueue> *pSceneGraph)
                {
                    if (pSceneGraph)
                    {
                        _SafeDelete(m_pSceneGraph);
                        m_pSceneGraph = pSceneGraph;
                    }
                    return true;
                }

            protected:
                CSceneGraph<TObj, TRenderQueue> *m_pSceneGraph;
            };

            /////////////////////////////////////////////////
            // Scene manager class definition
            template<typename TObj, typename TRenderQueue>
            CSceneManager<TObj, TRenderQueue>::~CSceneManager()
            {
                Clear();
                _SafeDelete(m_pSceneGraph);
            }

            template<typename TObj, typename TRenderQueue>
            bool CSceneManager<TObj, TRenderQueue>::AddObj(const std::string &name, boost::shared_ptr<TObj> &pObj)
            {
                if (_CManagerBase<TObj>::AddObj(name, pObj))
                {
                    if (m_pSceneGraph && m_pSceneGraph->AddObj(pObj))
                        return true;
                }
                return false;
            }

            template<typename TObj, typename TRenderQueue>
            void CSceneManager<TObj, TRenderQueue>::RemoveObj(const std::string &name)
            {
                _CManagerBase<TObj>::RemoveObj(name);
                if (m_pSceneGraph)
                    m_pSceneGraph->RemoveObj(pObj);
            }

            template<typename TObj, typename TRenderQueue>
            void CSceneManager<TObj, TRenderQueue>::Clear()
            {
                _CManagerBase<TObj>::Clear();
                if (m_pSceneGraph)
                    m_pSceneGraph->Clear();
            }

            template<typename TObj, typename TRenderQueue>
            HRESULT CSceneManager<TObj, TRenderQueue>::TraverseSceneGraph(const IMemberCaller<TObj> &func)
            {
                HRESULT hr;
                if (m_pSceneGraph)
                    V_RETURN( m_pSceneGraph->Traverse(func) );
                return hr;
            }

            template<typename TObj, typename TRenderQueue>
            void CSceneManager<TObj, TRenderQueue>::UpdateWorldCoord()
            {
                bool updated = false;
                BOOST_FOREACH(obj_ref_type obj, m_store)
                {
                    updated = obj.second->UpdateWorldCoord() || updated;
                }

                BOOST_FOREACH(obj_ref_type obj, m_store)
                {
                    obj.second->ResetUpToDateFlag();
                }

                if (updated && m_pSceneGraph)
                    m_pSceneGraph->NotifySceneUpdate();
            }


        } //namespace core
    } //namespace engine
} //namespace grflib